

#include <cstdlib>
#include <cassert>
#include <iostream>

#include "serialization.h"

/*
    
    C++实现二进制序列化/反序列化

    摘自 "https://www.cnblogs.com/Keeping-Fit/p/14952742.html"  [C++实现二进制序列化/反序列化]
    
    背景
        涉及对象传输或存储时，均需要序列化的参与，将对象转为连续的二进制数据后才能进行传输或存储，需要还原对象时，
        通过反序列化逆向处理二进制数据遍能得到原对象

        - 这里的对象是一种广泛的概念，往大了说就是一段有意义的内存

    实现
        - 实现过程中主要使用模板应对各种类型，特化+宏应对基础数据类型，逐层处理应对STL容器嵌套情况
        - C++语言本身不带反射，自定义结构需继承接口类Serializable，并实现相应接口
        - 实现时使用了std::move()进行构造与赋值，自定义结构最好实现自己的移动构造函数与移动赋值函数
        - 获取序列化buffer时，先计算序列化目标在序列化后的总字节数，一次性申请足够内存
        - 获取序列化buffer时，返回的buffer之前藏了序列化目标的总字节数，藏东西这招跟redis学的
        - 藏的目标总字节数目的用于，反序列化前简单判断待反序列化buffer是否有效
        - 未支持指针类型，传递错误类型的指针(强转目标类型与实际类型不符合)会导致内存错误，序列化过程中没法判断类型是否正确
        - 未支持C风格字符串，C风格字符串以0结尾，非二进制安全
        - 需要序列化一段连续内存时，构造std::string后传入
        - 反序列化时，调用者需自行保证，待反序列化buffer的原始类型与目标类型一致，代码不能识别出类型差异与结构改变
        - 使用方式 申请序列化buffer->序列化->三方库压缩->三方库加密->传输/落盘->接收/读取->三方库解密->三方库解压->简单检查->反序列化->释放buffer
        - 序列化后的数据格式如下
            . 先写入对象序列化后总长度，后面才接着写入对象序列化数据
                .. 对象是基础类型则直接写入数据
                .. 对象是STL容器先写入元素个数，再写入每个元素序列化数据
                     如果元素是std::pairl类型，则先写入序列化Key，再写入序列化Value
                .. 对象是自定义结构，则需用户定义数据格式
        总体结构：
        
*/

using namespace std;
using namespace Serialization;

template <typename T>
void Test(const T &a)
{
    std::cout << Serialization::Length(a) << std::endl;

    auto pBuffer = Serialization::GetBuffer(a);

    auto len = Serialization::Serialize(a, pBuffer);
    std::cout << len << std::endl;

    assert(1 == Serialization::CheckLength(pBuffer, Serialization::Length(a) + sizeof(Serialization::LEN)));

    T b = T();
    len = Serialization::UnSerialize(pBuffer, b);
    std::cout << len << std::endl;

    Serialization::ReleaseBuffer(pBuffer);
    assert(a == b);
    std::cout << std::endl;
}

class MyTest : public Serialization::Serializable
{
public:
    MyTest() : m_i(0), m_c(0), m_d(0) {}

    MyTest(int i, char c, double d, const std::string &str, const std::list<int> &list,
           const std::map<int, double> &map, const std::vector<int> &vec, const std::set<int> &set)
        : m_i(i), m_c(c), m_d(d), m_str(str), m_list(list), m_map(map), m_vec(vec), m_set(set) {}

    MyTest(int i, char c, double d, std::string &&str, std::list<int> &&list,
           std::map<int, double> &&map, std::vector<int> &&vec, std::set<int> &&set) //针对列表初始化
        : m_i(i), m_c(c), m_d(d), m_str(std::move(str)), m_list(std::move(list)), m_map(std::move(map)), m_vec(std::move(vec)), m_set(std::move(set))
    {
    }

    bool operator==(const MyTest &rhs) const
    {
        return m_i == rhs.m_i && m_c == rhs.m_c && m_d == rhs.m_d && m_str == rhs.m_str && m_list == rhs.m_list && m_map == rhs.m_map && m_vec == rhs.m_vec && m_set == rhs.m_set;
    }

    virtual unsigned Length() const override
    {
        return Serialization::Length(m_i) + Serialization::Length(m_c) + Serialization::Length(m_d) + Serialization::Length(m_str) + Serialization::Length(m_list) + Serialization::Length(m_map) + Serialization::Length(m_vec) + Serialization::Length(m_set);
    }
    virtual unsigned Serialize(char *const pBuffer) const override
    {
        unsigned uPos = 0;
        uPos += Serialization::Serialize(m_i, pBuffer + uPos);
        uPos += Serialization::Serialize(m_c, pBuffer + uPos);
        uPos += Serialization::Serialize(m_d, pBuffer + uPos);
        uPos += Serialization::Serialize(m_str, pBuffer + uPos);
        uPos += Serialization::Serialize(m_list, pBuffer + uPos);
        uPos += Serialization::Serialize(m_map, pBuffer + uPos);
        uPos += Serialization::Serialize(m_vec, pBuffer + uPos);
        uPos += Serialization::Serialize(m_set, pBuffer + uPos);
        return uPos;
    }
    virtual unsigned UnSerialize(const char *const pBuffer) override
    {
        unsigned uPos = 0;
        uPos += Serialization::UnSerialize(pBuffer + uPos, m_i);
        uPos += Serialization::UnSerialize(pBuffer + uPos, m_c);
        uPos += Serialization::UnSerialize(pBuffer + uPos, m_d);
        uPos += Serialization::UnSerialize(pBuffer + uPos, m_str);
        uPos += Serialization::UnSerialize(pBuffer + uPos, m_list);
        uPos += Serialization::UnSerialize(pBuffer + uPos, m_map);
        uPos += Serialization::UnSerialize(pBuffer + uPos, m_vec);
        uPos += Serialization::UnSerialize(pBuffer + uPos, m_set);
        return uPos;
    }

    // private:
public:
    int m_i;
    char m_c;
    double m_d;
    std::string m_str;
    std::list<int> m_list;
    std::map<int, double> m_map;
    std::vector<int> m_vec;
    std::set<int> m_set;
};

int main(int argc, char const *argv[])
{
    //基础类型
    Test<char>('a');
    Test<short>(-1);
    Test<int>(-1);
    Test<float>(-1.0);
    Test<long>(-1);
    Test<double>(-1.0);
    Test<long long>(-1);
    Test<unsigned char>(1);
    Test<unsigned short>(1);
    Test<unsigned int>(1);
    Test<unsigned long>(1);
    Test<unsigned long long>(1);

    cout << "====== 1 ======" << endl;

    //STL容器
    Test<std::string>("Test!!!");
    Test<std::list<int>>({1, 2, 3, 4, 5, 6});
    Test<std::map<int, double>>({{1, 1.0}, {2, 2.0}, {3, 3.0}});
    Test<std::vector<int>>({1, 2, 3, 4, 5, 6});
    Test<std::set<int>>({1, 2, 3, 4, 5, 6});

    cout << "====== 2 ======" << endl;

    //STL容器嵌套
    Test<std::set<std::string>>({"test1", "test2", "test3"});
    Test<std::list<std::set<std::string>>>(
        {{"test1", "test2", "test3"}, {"test1", "test2", "test3"}, {"test1", "test2", "test3"}});
    Test<std::map<int, std::list<std::set<std::string>>>>(
        {{1, {{"test1", "test2", "test3"}, {"test1", "test2", "test3"}, {"test1", "test2", "test3"}}},
         {2, {{"test1", "test2", "test3"}, {"test1", "test2", "test3"}, {"test1", "test2", "test3"}}},
         {3, {{"test1", "test2", "test3"}, {"test1", "test2", "test3"}, {"test1", "test2", "test3"}}}});
    Test<std::vector<std::map<int, std::list<std::set<std::string>>>>>(
        {{{1, {{"test1", "test2", "test3"}, {"test1", "test2", "test3"}, {"test1", "test2", "test3"}}},
          {2, {{"test1", "test2", "test3"}, {"test1", "test2", "test3"}, {"test1", "test2", "test3"}}},
          {3, {{"test1", "test2", "test3"}, {"test1", "test2", "test3"}, {"test1", "test2", "test3"}}}},
         {{1, {{"test1", "test2", "test3"}, {"test1", "test2", "test3"}, {"test1", "test2", "test3"}}},
          {2, {{"test1", "test2", "test3"}, {"test1", "test2", "test3"}, {"test1", "test2", "test3"}}},
          {3, {{"test1", "test2", "test3"}, {"test1", "test2", "test3"}, {"test1", "test2", "test3"}}}},
         {{1, {{"test1", "test2", "test3"}, {"test1", "test2", "test3"}, {"test1", "test2", "test3"}}},
          {2, {{"test1", "test2", "test3"}, {"test1", "test2", "test3"}, {"test1", "test2", "test3"}}},
          {3, {{"test1", "test2", "test3"}, {"test1", "test2", "test3"}, {"test1", "test2", "test3"}}}}});

    cout << "====== 3 ======" << endl;

    //自定义结构
    MyTest test(1, 'a', 1.0, "Test!!!", {1, 2, 3, 4, 5, 6}, {{1, 1.0}, {2, 2.0}, {3, 3.0}}, {1, 2, 3, 4, 5, 6}, {1, 2, 3, 4, 5, 6});
    Test<MyTest>(test);

    unsigned int size = test.Length();
    char *alloc_buf = new char[size];
    test.Serialize(alloc_buf);

    MyTest unserialize_test;
    unserialize_test.UnSerialize(alloc_buf);
    delete[] alloc_buf;

    cout << unserialize_test.m_i << " " << unserialize_test.m_c << " "
         << unserialize_test.m_d << " " << unserialize_test.m_str << " "
         << endl;
    for (int &item : unserialize_test.m_list)
    {
        cout << item << " ";
    }
    cout << endl;

    for (std::pair<const int, double> &item : unserialize_test.m_map)
    {
        cout << item.first << ":" << item.second << " ";
    }
    cout << endl;

    for (int &item : unserialize_test.m_vec)
    {
        cout << item << " ";
    }
    cout << endl;

    for (const int &item : unserialize_test.m_set)
    {
        cout << item << " ";
    }
    cout << endl;

    system("pause");

    return 0;
}
